import Cell from "./Cell";
import { TableStore, ColumnProps, TableContextKey } from '.';
import Colgroup from "./Colgroup";
import { VirtualListCore } from "../virtual-list";
import { PropType, computed, defineComponent, inject, onMounted, ref, watchEffect } from "vue";

type BodyProps = {
    data: TableStore,
    onScroll: (scrollLeft: number, clientWidth: number, scrollWidth: number) => void,
    height?: number,
    virtual?: boolean
}

type RowProps = {
    store: TableStore,
    data: any,
    index: number,
    ref?: any
}

export const Row = defineComponent({
    name: 'Row',
    props: {
        store: {type: Object as PropType<RowProps['store']>},
        data: {type: Object as PropType<RowProps['data']>},
        index: {type: Number as PropType<RowProps['index']>}
    },
    setup (props) {
        const ctx: any = inject(TableContextKey, null);
        const onRowClick = () => {
            if (props.data._type === 'expandChildren') {
                return;
            }
            // 设置了highlight属性才能进行高亮
            if (ctx && ctx.highlight) {
                ctx.onSelectRow(props.data);
            }
        };
        const classList = computed(() => ({
            'cm-table-row': true,
            'cm-table-row-ood': props.index % 2 === 0,
            'cm-table-row-even': props.index % 2 !== 0,
            'cm-table-row-selected': props.data._highlight
        }));

        const rowStyle = computed(() => ({
            display: props.data._show ? '' : 'none',
        }));
        return () => <tr class={classList.value} onClick={onRowClick} style={rowStyle.value}>
            {
                props.data._type === 'expandChildren'
                    ? <Cell type="td" data={props.data} column={props.data.column} index={props.index}
                        showFixedLeft={props.store.showFixedLeft}
                        showFixedRight={props.store.showFixedRight} colSpan={props.store.columns.length}/>
                    : props.store.columns.map((column, columnIndex) => {
                        let [rowSpan, colSpan] = [1, 1];
                        if (ctx && ctx.spanMethod) {
                            const ret = ctx.spanMethod(props.data, column, props.index, columnIndex);
                            if (ret) {
                                [rowSpan, colSpan] = ret;
                            }
                        }
                        return rowSpan && colSpan ?
                            <Cell type="td" data={props.data} column={column} index={props.index} colIndex={columnIndex}
                                showFixedLeft={props.store.showFixedLeft}
                                showFixedRight={props.store.showFixedRight} rowSpan={rowSpan} colSpan={colSpan}/>
                            : null;
                    })
            }
        </tr>;
    }
});

export const EmprtyRow = defineComponent({
    name: 'EmptyRow',
    props: {store: Object},
    setup (props) {
        const ctx: any = inject('CMTableContext', null);
        return () => <tr>
            <td colspan={props.store.columns.length}>
                <div class="cm-table-emprty-cell">{ ctx?.empty || '暂无数据'}</div>
            </td>
        </tr>;
    }
});

const VirtualItem = (props) => {
    const rowData = props.item;
    return <Row key={rowData.id} data={rowData} index={props.index} store={props.store}/>;
};
VirtualItem.displayName = 'VirtualItem';

export default defineComponent({
    name: 'Body',
    props: {
        data: {type: Object as PropType<BodyProps['data']>},
        height: {type: Number as PropType<BodyProps['height']>},
        virtual: {type: Boolean as PropType<BodyProps['virtual']>},
    },
    emits: ['scroll'],
    setup (props, { emit }) {
        const body = ref();
        const height = ref<number>();
        const width = () => {
            const columns = props.data.columns;
            let total = 0;
            columns.forEach((item: ColumnProps) => {
                total += item._width || 0;
            });
            return total;
        };

        watchEffect(() => {
            // 数据改变也需要重刷
            props.data.data;
            const hh = props.data.headerSize.height;
            const summaryH = props.data.summarySize.height;

            if (props.virtual) {
                const scrollElHeight = props.height ?? document.documentElement.clientHeight;
                height.value = scrollElHeight - hh - summaryH;
            } else {
                setTimeout(() => {
                    const content = body.value.querySelector('.cm-table-body-wrap');
                    const contentH = content.getBoundingClientRect().height;
                    if (props.height && contentH > props.height - hh - summaryH) {
                        const bodyH = props.height - hh - summaryH;
                        height.value = bodyH;
                    }
                });
            }
        });

        const handleScroll = () => {
            emit('scroll', body.value.scrollLeft, body.value.clientWidth, body.value.scrollWidth);
        };
        const contentElement = ref();
        const bodyElement = ref();

        return () => <div class="cm-table-body" ref={body} onScroll={handleScroll}
            style={{display: 'block', 'width': '100%', overflow: 'auto', height: height.value + 'px', position: 'relative'}}>
            {
                props.virtual ?
                    <div ref={contentElement} style={{'min-width': '100%', width: width() + 'px', 'will-change': 'transform', 'box-sizing': 'border-box', 'contain': 'strict',
                        position: 'absolute', top: 0,left: 0}}>
                        <table class="cm-table-body-wrap">
                            <Colgroup data={props.data}/>
                            <thead style={{display: 'none'}}>
                                <tr>
                                    {
                                        props.data.columns.map((col, index) => {
                                            return <Cell column={col} type="th" placeholder colIndex={index} checkedAll={props.data.checkedAll}/>;
                                        })
                                    }
                                </tr>
                            </thead>
                            <tbody ref={bodyElement}>
                                {
                                    body.value
                                        ? <VirtualListCore scrollElement={body.value} contentElement={contentElement.value} bodyElement={bodyElement.value}
                                            items={props.data.data} itemEstimatedSize={50} maxHeight={height.value || props.height}>
                                            {{
                                                default: (scope) => {
                                                    return <Row key={scope.item.id} data={scope.item} index={scope.index} store={props.data}/>;
                                                }
                                            }}
                                        </VirtualListCore>
                                        : null
                                }

                                {
                                    !props.data.data || !props.data.data.length
                                        ? <EmprtyRow store={props.data}/> : null
                                }
                            </tbody>
                        </table>
                    </div>
                    : <table class="cm-table-body-wrap" ref={bodyElement}>
                        <Colgroup data={props.data}/>
                        <thead style={{display: 'none'}}>
                            <tr>
                                {
                                    props.data.columns.map((col, index) => {
                                        return <Cell column={col} type="th" placeholder colIndex={index} checkedAll={props.data.checkedAll}/>;
                                    })
                                }
                            </tr>
                        </thead>
                        <tbody>
                            {
                                props.data.data.map((rowData: any, index: number) => {
                                    return <Row key={rowData.id} data={rowData} index={index} store={props.data} />;
                                })
                            }
                            {
                                !props.data.data || !props.data.data.length
                                    ? <EmprtyRow store={props.data}/> : null
                            }
                        </tbody>
                    </table>
            }
        </div>;
    }
});
